package pl.alipiec.stockview.naming;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class HTTPNaming {
	public static void main(String[] args) throws IOException {
		InetSocketAddress addr = new InetSocketAddress(8080);
		HttpServer server = HttpServer.create(addr, 0);

		System.out.println("Starting server...");

		server.createContext("/", new IndexesHandler());
		server.setExecutor(Executors.newCachedThreadPool());
		server.start();

		System.out.println("Server is listening on port 8080");
	}
}

class IndexData {
	public String name = null;
	public String host = "localhost";
	public int port = 61613;
	public String topic = null;
}

class IndexesHandler implements HttpHandler {
	
	private Map<String, IndexData> indexMap;
	
	
	public IndexesHandler() {
		indexMap = new HashMap<String, IndexData>();
	}

	public void handle(HttpExchange exchange) throws IOException {
		String requestMethod = exchange.getRequestMethod();

		Headers responseHeaders = exchange.getResponseHeaders(); 
		responseHeaders.set("Content-Type", "application/json"); 
		
		OutputStream responseBody = exchange.getResponseBody();
		String path = exchange.getRequestURI().getPath();
		
		System.out.println("Responding " + path);
		
		if (requestMethod.equalsIgnoreCase("GET")) {
			try {
				if (path.equals("/indexes/list"))
					handleList(exchange, responseBody);
				else if (path.equals("/indexes/register"))
					handleRegister(exchange, responseBody);
				else if (path.equals("/indexes/unregister"))
					handleUnregister(exchange, responseBody);
				else
					handleNotFound(exchange, responseBody);
			} catch (Exception e) {
				e.printStackTrace();
				handleError(exchange, responseBody);
			}
		} else {
			handleNotImplemented(exchange, responseBody);
		}
		
		responseBody.close();
	}

	private void handleList(HttpExchange exchange, OutputStream responseBody) throws IOException {
		StringBuilder sb = new StringBuilder();
		
		boolean first = true;
		sb.append("[\n");
		for (IndexData data : indexMap.values()) {
			if (first) {
				first = false;
				sb.append("\t{\n");
			} else {
				sb.append(",\n\t{\n");
			}
			sb.append("\t\t\"name\": ").append('"').append(data.name).append("\",\n");
			sb.append("\t\t\"host\": ").append('"').append(data.host).append("\",\n");
			sb.append("\t\t\"port\": ").append(data.port).append(",\n");
			sb.append("\t\t\"topic\": ").append('"').append(data.topic).append("\"\n");
			sb.append("\t}");
		}
		sb.append("\n]\n");
		
		exchange.sendResponseHeaders(200, 0);
		responseBody.write(sb.toString().getBytes());
	}

	private void handleRegister(HttpExchange exchange, OutputStream responseBody) throws IOException {
		IndexData data = new IndexData();
		
		String query = exchange.getRequestURI().getQuery();
		String[] params = query.split("&");
		for (String param : params) {
			String[] nv = param.split("=");
			if (nv[0].equals("name"))
				data.name = nv[1];
			else if (nv[0].equals("host"))
				data.host = nv[1];
			else if (nv[0].equals("port"))
				data.port = Integer.parseInt(nv[1]);
			else if (nv[0].equals("topic"))
				data.topic = nv[1];
		}
		
		if (data.name == null || data.topic == null) {
			exchange.sendResponseHeaders(400, 0);
			responseBody.write("name and topic required".getBytes());
			return ;
		}
		
		if (indexMap.containsKey(data.name)) {
			indexMap.put(data.name, data);
			exchange.sendResponseHeaders(200, 0);
			responseBody.write("updated".getBytes());			
		} else {
			indexMap.put(data.name, data);
			exchange.sendResponseHeaders(200, 0);
			responseBody.write("added".getBytes());			
		}
	}

	private void handleUnregister(HttpExchange exchange, OutputStream responseBody) throws IOException {
		String name = null;
		
		String query = exchange.getRequestURI().getQuery();
		String[] params = query.split("&");
		for (String param : params) {
			String[] nv = param.split("=");
			if (nv[0].equals("name"))
				name = nv[1];
		}
		
		if (name == null) {
			exchange.sendResponseHeaders(400, 0);
			responseBody.write("name required".getBytes());
			return ;
		}
		
		if (indexMap.containsKey(name)) {
			indexMap.remove(name);
			exchange.sendResponseHeaders(200, 0);
			responseBody.write("removed".getBytes());			
		} else {
			exchange.sendResponseHeaders(200, 0);
			responseBody.write("not found".getBytes());			
		}
	}

	private void handleNotFound(HttpExchange exchange, OutputStream responseBody) throws IOException {
		exchange.sendResponseHeaders(404, 0);
		responseBody.write("not found".getBytes());
	}
	
	private void handleError(HttpExchange exchange, OutputStream responseBody) throws IOException {
		exchange.sendResponseHeaders(500, 0);
		responseBody.write("internal error".getBytes());
	}
	
	private void handleNotImplemented(HttpExchange exchange, OutputStream responseBody) throws IOException {
		exchange.sendResponseHeaders(501, 0);
		responseBody.write("method not supported".getBytes());
	}
}
